#include "UtilityPCH.h"
#include "UT_SampleHelper.h"
#include "UT_MathHelper.h"

using namespace Utility;
//-----------------------------------------------------------------
void UT_SampleHelper::SampleStratified1D(float *samp, int32_t nSamples, UT_RandomNumGenerator &rng,bool jitter)
{
	float invTot = 1.f / nSamples;
	for (int32_t i = 0;  i < nSamples; ++i)
	{
		float delta = jitter ? rng.RandomFloat() : 0.5f;
		*samp++ = UT_MathHelper::Min((i + delta) * invTot, UT_MathDefine::_ONE_MINUS_EPSILON);
	}
}
//-----------------------------------------------------------------
void UT_SampleHelper::SampleStratified2D(float *samples, int32_t nx, int32_t ny, UT_RandomNumGenerator& rng, bool jitter /* = true */)
{
	float dx = 1.f / nx, dy = 1.f / ny;
	for(int32_t y = 0; y < ny; ++y)
	{
		for(int32_t x = 0; x < nx; ++x)
		{
			float jx = jitter ? rng.RandomFloat() : 0.5f;
			float jy = jitter ? rng.RandomFloat() : 0.5f;

			*samples++ = UT_MathHelper::Min((x+jx)*dx,UT_MathDefine::_ONE_MINUS_EPSILON);
			*samples++ = UT_MathHelper::Min((y+jy)*dy,UT_MathDefine::_ONE_MINUS_EPSILON);
		}
	}
}
//-----------------------------------------------------------------
void UT_SampleHelper::SampleLatinHypercube(float *samples, uint32_t nSamples, uint32_t nDim, UT_RandomNumGenerator &rng)
{
	// Generate LHS samples along diagonal
	float delta = 1.f / nSamples;
	for (uint32_t i = 0; i < nSamples; ++i)
		for (uint32_t j = 0; j < nDim; ++j)
			samples[nDim * i + j] = UT_MathHelper::Min((i + (rng.RandomFloat())) * delta,UT_MathDefine::_ONE_MINUS_EPSILON);

	// Permute LHS samples in each dimension
	for (uint32_t i = 0; i < nDim; ++i)
	{
		for (uint32_t j = 0; j < nSamples; ++j)
		{
			uint32_t other = j + (rng.RandomUInt() % (nSamples - j));
			ut_swap(samples[nDim * j + i], samples[nDim * other + i]);
		}
	}
}
//-----------------------------------------------------------------
double UT_SampleHelper::RadicalInverse(int32_t n, int32_t base)
{
	double val = 0;
	double invBase = 1. / base, invBi = invBase;
	while (n > 0)
	{
		// Compute next digit of radical inverse
		int d_i = (n % base);
		val += d_i * invBi;
		n *= invBase;
		invBi *= invBase;
	}
	return val;
}
//-----------------------------------------------------------------
double UT_SampleHelper::PermutedRadicalInverse(int32_t n, int32_t base,const uint32_t *permuteTable)
{
	double val = 0;
	double invBase = 1. / base, invBi = invBase;

	while (n > 0)
	{
		uint32_t d_i = permuteTable[n % base];
		val += d_i * invBi;
		n *= invBase;
		invBi *= invBase;
	}
	return val;
}
//-----------------------------------------------------------------
void UT_SampleHelper::GeneratePermutation(uint32_t *buf, uint32_t b, UT_RandomNumGenerator &rng)
{
	for (uint32_t i = 0; i < b; ++i)
		buf[i] = i;
	
	ShuffleSamples(buf, b, 1, rng);
}
//-----------------------------------------------------------------
//-----------------------------------------------------------------
//-----------------------------------------------------------------